﻿using System;
using System.Runtime.CompilerServices;
using RayDen.Library.Core;
using RayDen.RayEngine.Core.Interface;
using RayDen.RayEngine.Core.Types;

namespace RayDen.RayEngine.Samplers
{
    public class PhotonMappingContextSampler : ISampler
    {
        public static int PreviewPasses = 1;
        public static int SamplesPerPassX4 = 16;
        public static int SuperSamplingSize = 4;
        public static int MagicValue2 = 16;
        public int Width { get; protected set; }
        public int Height { get; protected set; }

        public int screenWidth, screenHeight, screenStartLine;
        int currentSampleScreenX, currentSampleScreenY, currentSubSampleIndex;
        public int pass;
        public bool lowLatency;
        public int valuesPerSample;

        private IRandomProvider rnd;

        public int tIdx;



        public PhotonMappingContextSampler()
        {
            rnd =
                new FastRandom();
            //new HaltonSequence();
            TotalSamples = 0L;
        }

        int ScreenHeight
        {
            get { return screenStartLine + screenHeight; }
        }

        public Sample GetSample(Sample prevSample)
        {
            TotalSamples++;
            Sample sample = new Sample(this);
            int scrX, scrY;


            // In order to improve ray coherency
            int stepX = currentSubSampleIndex % SuperSamplingSize;
            int stepY = currentSubSampleIndex / SuperSamplingSize;

            scrX = currentSampleScreenX;
            scrY = currentSampleScreenY;

            currentSubSampleIndex++;
            if (currentSubSampleIndex == (SamplesPerPassX4))
            {
                currentSubSampleIndex = 0;
                currentSampleScreenX++;
                if (currentSampleScreenX >= screenWidth)
                {
                    currentSampleScreenX = 0;
                    currentSampleScreenY++;

                    if (currentSampleScreenY >= ScreenHeight)
                    {
                        currentSampleScreenY = Math.Max(0, screenStartLine - 1);
                        pass += SamplesPerPassX4;
                    }
                }
            }

            float r1 = (stepX + ((float)rnd.NextDouble())) / SuperSamplingSize - 0.5f;
            float r2 = (stepY + ((float)rnd.NextDouble())) / SuperSamplingSize - 0.5f;
            sample.imageX = scrX + r1;
            sample.imageY = scrY + r2;
            //sample.imageY += screenStartLine;

            //sample.Init(this,pass, valuesPerSample, false);
            return sample;

        }


        #region ISampler Members


        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public float GetLazyValue(Sample sample)
        {
            return rnd.NextFloat();
        }

        public float GetLDValue(Sample sample)
        {
            return rnd.NextFloat();

        }

        public void Init(int width, int height)
        {
            rnd.Reinitialise((int)DateTime.Now.Ticks);
            if (screenWidth == 0 && screenHeight == 0)
            {
                Width = screenWidth = width;
                Height = screenHeight = height;
                screenWidth = width;
                screenHeight = height;
            }
            screenStartLine = Math.Max(0, screenStartLine - 1);
            currentSubSampleIndex = 0;
            pass = 0;
            TotalSamples = 0;
        }

        public int GetPass()
        {
            return pass;
        }

        public long TotalSamples { get; set; }
        public float GetLazyValue(Sample sample, int index)
        {
            return sample.sampleData[unchecked(index)];
        }


        #endregion

        public void Reinitialise(int seed)
        {
            this.rnd.Reinitialise(seed);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public float NextFloat()
        {
            return rnd.NextFloat();
        }
    }
}